package db_utils

import (
	"database/sql"
	"dgo/goutils/utils"
	"fmt"
	"os"
	"reflect"
	"time"
	"unsafe"
)

const (
	check_table_exists       string = "select 1 from %s where 1=0"
	check_table_field_exists string = "select %s from %s where 1=0"
)

func ExtractRowsAndColumns(rows *sql.Rows) ([][]SqlValue, []string, error) {
	rval := make([][]SqlValue, 0, 1024)
	columns, _ := rows.Columns()
	for rows.Next() {
		rowValues, err := GetRowValues(rows)
		if err != nil {
			return nil, columns, err
		}
		rval = append(rval, rowValues)
	}

	return rval, columns, nil
}

func ForeachRows(rows [][]SqlValue, rowEach func(row []SqlValue, idx int) bool) {
	for k, v := range rows {
		if !rowEach(v, k) {
			break
		}
	}
}

func ExtractSQLValue(realV interface{}) interface{} {
	switch s := realV.(type) {
	case []byte:
		return string(s)
	case time.Time:
		return s
	case int:
	case int32:
	case int8:
	case int64:
		return s
	case bool:
		return s
	case nil:
		return s
	default:
		return utils.GetStrValue(s, "")
	}

	return realV
}

func AssignObjFromRec(obj interface{}, row []SqlValue, cols []string) error {
	v := reflect.ValueOf(obj)
	vk := v.Kind()
	if vk != reflect.Ptr {
		return fmt.Errorf("obj必须为结构体指针")
	}

	elem := v.Elem()
	vtype := elem.Type()
	for i := 0; i < elem.NumField(); i++ {
		fd := vtype.Field(i)
		elemfd := elem.Field(i)
		str := fd.Tag.Get("field")
		if len(str) == 0 {
			str = fd.Tag.Get("id")
		}
		if len(str) == 0 {
			str = fd.Name
		}
		idx := utils.StrIndex(str, cols...)
		if idx == -1 {
			continue
		}
		kd := elemfd.Kind()
		if kd == reflect.String {
			*(*string)(unsafe.Pointer(elemfd.Addr().Pointer())) = row[idx].AsString("")
		} else if kd == reflect.Float64 || kd == reflect.Float32 {
			elemfd.SetFloat(row[idx].AsFloat64(0))
		} else if kd == reflect.Int64 || kd == reflect.Int || kd == reflect.Int8 ||
			kd == reflect.Int16 {
			elemfd.SetInt(row[idx].AsInt64(0))
		} else if kd == reflect.Uint32 {
			elemfd.SetUint(uint64(row[idx].AsInt64(0)))
		} else {
			if fd.Type == utils.REFLECT_TYPE_TIME {
				elemfd.Set(reflect.ValueOf(row[idx].AsDateTime(utils.ZeroTime)))
			}
			fmt.Fprintf(os.Stderr, "unkown type:%v", fd.Type)
		}
	}
	return nil
}
